<?php

declare(strict_types=1);
/**
 * This file is part of habo_new_media.
 *
 * @link     https://www.berlen.cn/
 * @contact  tech@berlen.cn
 * @license  http://gitlab.rehou.cn/habo/habo_new_media/-/blob/master/README.md
 */
namespace app\service\analysis\data\material;

use app\enum\AnalysisEnum;
use app\model\mongo\MongoInfoModel;
use app\model\mongo\MongoReportModel;
use app\service\analysis\report\ReportPicService;
use app\service\analysis\report\ReportVideoService;
use app\service\BaseService;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Cache;

final class MaterialStatService extends BaseService
{
    /**
     * @var int 队列最大长度
     */
    private const MAX_LEN = 500;

    /**
     * @var int 媒体类型
     */
    private int $mediaId;

    /**
     * @var int 任务类型
     */
    private int $taskType;

    /**
     * @var null|ReportPicService|ReportVideoService 素材报表
     */
    private $service;

    /**
     * @var array|mixed 缓存键值
     */
    private array $queueKey = AnalysisEnum::TASK_QUEUE_LIST['material_day_stat'];

    /**
     * @var null|MongoReportModel 素材报表模型
     */
    private ?MongoReportModel $model;

    public function __construct(int $mediaId = 0, int $taskType = 0)
    {
        $this->mediaId = $mediaId;
        $this->taskType = $taskType;
        $this->setService();
    }

    /**
     * 判断是否是服务
     */
    public function isService(): bool
    {
        return $this->service && $this->service->isService();
    }

    /**
     * 待归档数据.
     * @return array|Collection|MongoReportModel[]
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getList()
    {
        $redis = Cache::store('redis')->handler();
        if ($this->queueKey[$this->taskType][$this->mediaId]) {
            $len = $redis->hLen($this->queueKey[$this->taskType][$this->mediaId]);
            if ($len > self::MAX_LEN) {
                return [];
            }
        } else {
            return [];
        }
        return $this->service->getWaitArchiveList();
    }

    /**
     * 任务执行.
     */
    public function runTask(MongoReportModel $model): bool
    {
        $this->model = $model;
        if (! $this->model->getKey()) {
            return self::setError('未知日报信息');
        }

        if ($this->model->getAttr('is_sync') != MongoReportModel::SYNC_YES) {
            return self::setError('日报未同步完成');
        }

        if ($this->service->getIsSystem($model) == MongoInfoModel::IS_SYSTEM_MATERIAL) {
            if (! $this->setMaterialStat()) {
                return self::setError('设置素材汇总失败');
            }
        }

        return $this->setReportArchive();
    }

    /**
     * 设置素材汇总.
     */
    private function setMaterialStat(): bool
    {
        if (empty($this->model->getAttr('signature'))) {
            return true;
        }
        $redis = Cache::store('redis')->handler();
        if ($this->queueKey[$this->taskType][$this->mediaId]) {
            $value = json_encode([$this->mediaId, $this->taskType, $this->model->getAttr('signature'), $this->model->getAttr('stat_date')]);
            $field = md5($value);
            if (! $redis->hExists($this->queueKey[$this->taskType][$this->mediaId], $field)) {
                $redis->hSetnx($this->queueKey[$this->taskType][$this->mediaId], $field, $value);
            }
        }
        return true;
    }

    /**
     * 设置服务
     */
    private function setService()
    {
        if ($this->taskType == AnalysisEnum::TASK_TYPE_VIDEO) {
            $this->service = new ReportVideoService($this->mediaId);
        } elseif ($this->taskType == AnalysisEnum::TASK_TYPE_PICTURE) {
            $this->service = new ReportPicService($this->mediaId);
        }
    }

    /**
     * 设置日报同步完成.
     */
    private function setReportArchive(): bool
    {
        $this->model->setAttr('is_archive', MongoReportModel::ARCHIVE_YES);
        return $this->model->save();
    }
}
